package org.eda2;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.util.Set;

// Clase implementada, para realizar la lectura desde un archivo de texto,
// para cargar los usuarios que conforman el estudio de la practica.
/**
 * Clase InOut. Clase que genera los ficheros de texto de las soluciones.
 */
public class InOut {

	/**
	 * The error. Lista de errores. Arrays de int.
	 */
	private ArrayList<Integer> error;

	/**
	 * The fileName. Nombre del fichero de texto, sobre el que se realiza la
	 * lectura.
	 */
	private File fileName;

	/**
	 * The userlist. Lista de usuarios que crearemos con la lectura del fichero
	 * de texto.
	 */
	private ArrayList<User> userList;

	/**
	 * The badUsers. Lista de usuarios que crearemos con la lectura del fichero
	 * de texto, con erreros en sus datos.
	 */
	private ArrayList<User> badUsers;

	/**
	 * Metodo constructor de la clase InOut.
	 * 
	 * @param file
	 *            . Variable de tipo String. Hace referencia al nombre del
	 *            fichero sobre el que realizaremos la lectura.
	 */
	public InOut(String file) {
		// Inicializamos el fichero y todas las listas.
		this.fileName = new File(file);
		this.userList = new ArrayList<User>();
		this.badUsers = new ArrayList<User>();
		this.error = new ArrayList<Integer>();
	}

	/**
	 * Metodo readFile. Metodo que realiza la lectura desde el fichero de texto,
	 * para generar las respectivas listas.
	 */
	public void readFile() {
		int contador = 0;
		int longitud = 0;
		try {
			@SuppressWarnings("resource")
			BufferedReader in = new BufferedReader(new FileReader(fileName));
			String cadena = "";
			Scanner cadena1;
			int ice, ce = 0;
			// Obtenemos el numero de usuarios del fichero...
			longitud = Integer.parseInt(in.readLine());
			while ((cadena = in.readLine()) != null) {
				try {
					// Obtenemos los valores de ICE y CE, de cada linea,
					// correspondiente a cada usuario
					cadena1 = new Scanner(cadena).useDelimiter("\\s*,\\s*");
					ice = cadena1.nextInt();
					ce = cadena1.nextInt();
				} catch (Exception e) {
					// Si existen errores en los datos, insertamos dicho usuario
					// en la lista de usuarios con problemas....
					badUsers.add(new User("User" + contador, -1, -1));
					error.add(2);// Error de parseo de los atributos de un user
					contador++;
					continue;
				}
				// Si no existen errores se inserta en la lista de usuarios...
				if ((ice > 10000 || ice < 100) || (ce < 1 || ce > 1000)) {
					badUsers.add(new User("User" + contador, ice, ce));
					error.add(2);// Error de parseo de los atributos de un user
					contador++;
					continue;
				}
				userList.add(new User("User" + contador, ice, ce));
				contador++;
			}
		} catch (Exception e) {
			// Si no se puede realizar la lectura del numero de usuarios o no
			// existe el fichero....
			error.add(1);
		}
		if (contador != longitud)
			// No coincide el numero de usuarios con el numero de lineass del
			// fichero...
			error.add(3);
		if (error.contains(2))
			// Si existe errores de los datos de los usuarios, se llama al
			// metodo que generarar un fichero con aquellos usuarios con datos
			// erroneos...
			generarFicheroBadUsers();
	}

	/**
	 * Metodo generarFicheroBadUsers. Metodo que genera un fichero con el mismo
	 * formato que el de lectura, con quellos usuarios que el fichero original
	 * contenia datos ilegibles en su lectura.
	 */
	private void generarFicheroBadUsers() {
		// Localizamos el lugar para la creacion del fichero...
		String outputDirectory = System.getProperty("user.dir");
		outputDirectory = outputDirectory + File.separator + "src"
				+ File.separator + "org" + File.separator + "eda2"
				+ File.separator + "errores" + File.separator
				+ "SolucionBadUsers.txt";
		try {
			BufferedWriter out = new BufferedWriter(new FileWriter(
					outputDirectory));
			// La primera linea es el numero de usuarios con problemas...
			String numero = badUsers.size() + "";
			out.write(numero);
			out.newLine();
			// Para cada usuario de la lista de usuarios con problemas,
			// insertamos una linea con el nombre de dicho usuario con
			// problemas...
			for (int i = 0; i < badUsers.size(); i++) {
				String cadena = badUsers.get(i).getName();
				out.write(cadena);
				if (i < badUsers.size() - 1)
					out.newLine();
			}
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Metodo guardarUsuarios. Metodo que guarda una lista de usuarios de pareto
	 * en un fichero de texto, segun un determinado formato.
	 * 
	 * @param aux
	 *            . Variable de tipo ArrayList. Hace referencia a la lista de
	 *            usuarios a guardar en el fichero de texo.
	 * @param inputDirectory
	 *            . Variable de tipo String. Hace referencia al nombre del
	 *            fichero de texto donde se va a guardar la lista de usuarios.
	 */
	public static void guardarUsuariosPareto(ArrayList<User> aux,
			String outputDirectory) {
		try {
			PrintWriter out = new PrintWriter(new FileWriter(outputDirectory));
			out.println(aux.size());
			for (User actual : aux) {
				out.println(actual.toString());
			}
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Metodo guardarUsuarios. Metodo que guarda una lista de usuarios en un
	 * fichero de texto, segun un determinado formato.
	 * 
	 * @param aux
	 *            . Variable de tipo ArrayList. Hace referencia a la lista de
	 *            usuarios a guardar en el fichero de texo.
	 * @param inputDirectory
	 *            . Variable de tipo String. Hace referencia al nombre del
	 *            fichero de texto donde se va a guardar la lista de usuarios.
	 */
	public static void guardarUsuariosGreedy(ArrayList<User> aux,
			String outputDirectory) {
		try {
			PrintWriter out = new PrintWriter(new FileWriter(outputDirectory));
			out.println(aux.size());
			for (User actual : aux) {
				out.println(actual.toStringMcl());
			}
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Metodo guardarUsuariosPDinamica. Metodo que guarda una lista de usuarios
	 * en un fichero de texto, segun un determinado formato.
	 * 
	 * @param aux
	 *            . Variable de tipo ArrayList. Hace referencia a la lista de
	 *            usuarios a guardar en el fichero de texo.
	 * @param inputDirectory
	 *            . Variable de tipo String. Hace referencia al nombre del
	 *            fichero de texto donde se va a guardar la lista de usuarios.
	 */
	public static void guardarUsuariosPDinamica(ArrayList<User> aux,
			String outputDirectory) {
		try {
			PrintWriter out = new PrintWriter(new FileWriter(outputDirectory));
			out.println("El numero de usuarios a inspeccionar es: "
					+ aux.size());
			int contador = 0;
			out.println("Usuario;ice;ce;mcl;diferencia;tmi");
			for (User actual : aux) {
				out.println(actual.toStringTiempoInspec());
				contador += actual.getDiferencia();
			}
			out.println();
			out.println("El beneficio total acumulado, con los usuarios que da tiempo a inspecionar es de: ");
			out.println(contador);
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Metodo getError. Metodo que devuelve el numero del error detectado de la
	 * lista de errores.
	 * 
	 * @return the error. Variable de tipo int.
	 */
	public ArrayList<Integer> getError() {
		return error;
	}

	/**
	 * Metodo setError. Metodo que modifica la lista de errores, por una nueva
	 * pasada por parametro.
	 * 
	 * @param error
	 *            . Variable de tipo ArrayList, hace referencia a la lista nueva
	 *            a modificar.
	 */
	public void setError(ArrayList<Integer> error) {
		this.error = error;
	}

	/**
	 * Metodo getUserList. Metodo que devuelve la lista de usuarios leidos desde
	 * el archivo de texto.
	 * 
	 * @return userList. Variable de tipo ArrayList. Hace referencia a la lista
	 *         de usuarios.
	 */
	public ArrayList<User> getUserList() {
		return userList;
	}

	/**
	 * Metodo setUserList. Metodo que modifica la lista de usuarios, por una
	 * pasada por parametro.
	 * 
	 * @param userList
	 *            . Variable de tipo ArrayList.
	 */
	public void setUserList(ArrayList<User> userList) {
		this.userList = userList;
	}

	/**
	 * Metodo getBadUsers. Metodo que devuelve la lista de usuarios con errores
	 * en la lectura del fichero de texto.
	 * 
	 * @return badUsers. Variable de tipo ArrayList. Hace referencia a la lista
	 *         de usuarios con erreres en la lectura del fichero de texto.
	 */
	public ArrayList<User> getBadUsers() {
		return badUsers;
	}

	/**
	 * Metodo setBadUsers. Metodo que modifica la lista de usuarios con errores
	 * por una nueva pasada por parametro.
	 * 
	 * @param badUsers
	 *            . Variable de tipo ArrayList.
	 */
	public void setBadUsers(ArrayList<User> auxBadUsers) {
		this.badUsers = auxBadUsers;
	}

	public static void guardarRutasBackTraking(
			HashMap<Integer, ArrayList<User>> conjuntoDeRutas,
			String outputDirectory) {
		try {
			PrintWriter out = new PrintWriter(new FileWriter(outputDirectory));
			out.println("Conjunto de Rutas-Usuarios a Inspeccionar ");
			Set<Integer> keys = conjuntoDeRutas.keySet();
			ArrayList<User> auxiliar = new ArrayList<User>();
			int contador = 1;
			for (Integer actual : keys) {
				auxiliar = conjuntoDeRutas.get(actual);
				if (auxiliar.size() != 0) {
					out.print("Ruta " + (contador) + " [");
					for (int i = 0; i < auxiliar.size(); i++) {
						out.print(auxiliar.get(i).getName());
						if (i < auxiliar.size() - 1){
							out.print(", ");
						}
						else {
							out.println("]");
							contador++;	
						}
					}
				}
			}
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
